package com.ikproducts.manualian.client.library;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;


public class CategoryManager {

	/**
	 * 内部フィールド
	 */
	private static CategoryManager _Instance = null;
	Document _Doc = null;
	int _ArrayWatchCurrent;
	public final static String PathSeparator = ";";

	/**
	 * コンストラクタ
	 */
	private CategoryManager(){
		_Doc = XMLParser.parse("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root>	<computer name=\"コンピュータ\" rangeEnd=\"71\" rangeStart=\"1\">		<download_install name=\"ダウンロード/インストール\" rangeEnd=\"2\" rangeStart=\"2\"/><programming rangeEnd=\"42\" rangeStart=\"3\" name=\"プログラミング\">			<languages name=\"言語等\" rangeEnd=\"24\" rangeStart=\"4\"><c_cplusplus name=\"C/C++\" rangeEnd=\"5\" rangeStart=\"5\"/><c_sharp name=\"C#\" rangeEnd=\"6\" rangeStart=\"6\"/><visual_basic name=\"VisualBasic\" rangeEnd=\"7\" rangeStart=\"7\"/><asp_net name=\"ASP.NET\" rangeEnd=\"8\" rangeStart=\"8\"/><dot_net_framework name=\".NET Framework\" rangeEnd=\"9\" rangeStart=\"9\"/><java name=\"Java\" rangeEnd=\"10\" rangeStart=\"10\"/><html name=\"HTML\" rangeEnd=\"11\" rangeStart=\"11\"/><xml name=\"XML\" rangeEnd=\"12\" rangeStart=\"12\"/><css name=\"CSS\" rangeEnd=\"13\" rangeStart=\"13\"/><php name=\"PHP\" rangeEnd=\"14\" rangeStart=\"14\"/><Ruby name=\"Ruby\" rangeEnd=\"15\" rangeStart=\"15\"/><RubyonRails name=\"Ruby on Railes\" rangeEnd=\"16\" rangeStart=\"16\"/><perl name=\"Perl\" rangeEnd=\"17\" rangeStart=\"17\"/><javaScript name=\"JavaScript\" rangeEnd=\"18\" rangeStart=\"18\"/><actionScript name=\"ActionScript\" rangeEnd=\"19\" rangeStart=\"19\"/><python name=\"Python\" rangeEnd=\"20\" rangeStart=\"20\"/><delphi name=\"Delphi\" rangeEnd=\"21\" rangeStart=\"21\"/><android name=\"Android\" rangeEnd=\"22\" rangeStart=\"22\"/>			<google_app_engine name=\"Google App Engine\" rangeEnd=\"23\" rangeStart=\"23\"/>				<azure name=\"Azure\" rangeEnd=\"24\" rangeStart=\"24\"/>				</languages>			<web_server name=\"Webサーバー\" rangeEnd=\"31\" rangeStart=\"25\">				<apache name=\"Apache\" rangeEnd=\"26\" rangeStart=\"26\"/>				<iis name=\"IIS\" rangeEnd=\"27\" rangeStart=\"27\"/>				<anhttpd name=\"ANHTTPD\" rangeEnd=\"28\" rangeStart=\"28\"/>				<jetty name=\"Jetty\" rangeEnd=\"29\" rangeStart=\"29\"/>				<tomcat name=\"Tomcat\" rangeEnd=\"30\" rangeStart=\"30\"/>				<web_server_others name=\"その他(Webサーバー)\" rangeEnd=\"31\" rangeStart=\"31\"/></web_server>							<tools name=\"ツール等\" rangeEnd=\"32\" rangeStart=\"32\">				</tools><version_admin name=\"バージョン管理\" rangeEnd=\"38\" rangeStart=\"33\">	<subversion name=\"Subversion\" rangeEnd=\"34\" rangeStart=\"34\"/>	<mercurial name=\"Mercurial\" rangeEnd=\"35\" rangeStart=\"35\"/>	<git name=\"git\" rangeEnd=\"36\" rangeStart=\"36\"/>	<cvs name=\"CVS\" rangeEnd=\"37\" rangeStart=\"37\"/>	<vss name=\"Visual Source Safe\" rangeEnd=\"38\" rangeStart=\"38\"/></version_admin>	<ide name=\"統合開発環境\" rangeEnd=\"42\" rangeStart=\"39\">		<eclipse name=\"Eclipse\" rangeEnd=\"40\" rangeStart=\"40\"/>		<visual_studio name=\"Visual Studio\" rangeEnd=\"41\" rangeStart=\"41\"/>		<net_beans name=\"NetBeans\" rangeEnd=\"42\" rangeStart=\"42\"/></ide></programming>		<database name=\"データベース\" rangeEnd=\"50\" rangeStart=\"43\"><sql_all name=\"SQL全般\" rangeEnd=\"44\" rangeStart=\"44\"/><Oracle name=\"Oracle\" rangeEnd=\"45\" rangeStart=\"45\"/>			<mysql name=\"MySQL\" rangeEnd=\"46\" rangeStart=\"46\"/>			<postgresql name=\"PostgreSQL\" rangeEnd=\"47\" rangeStart=\"47\"/>			<sql_server name=\"SQL Server\" rangeEnd=\"48\" rangeStart=\"48\"/>			<access name=\"Access\" rangeEnd=\"49\" rangeStart=\"49\"/><database_others name=\"その他(データベース)\" rangeEnd=\"50\" rangeStart=\"50\"/>			</database>		<os name=\"OS\" rangeEnd=\"56\" rangeStart=\"51\">			<windows name=\"Windows\" rangeEnd=\"52\" rangeStart=\"52\"/>			<mac name=\"Mac\" rangeEnd=\"53\" rangeStart=\"53\"/>			<linux name=\"Linux\" rangeEnd=\"54\" rangeStart=\"54\"/>			<unix name=\"Unix\" rangeEnd=\"55\" rangeStart=\"55\"/>			<os_others name=\"その他(OS)\" rangeEnd=\"56\" rangeStart=\"56\"/></os>		<software name=\"ソフトウェア\" rangeEnd=\"57\" rangeStart=\"57\"/><hardware name=\"ハードウェア\" rangeEnd=\"58\" rangeStart=\"58\"/><network name=\"ネットワーク技術\" rangeEnd=\"59\" rangeStart=\"59\"/>		<browser name=\"ブラウザ\" rangeEnd=\"68\" rangeStart=\"60\">			<ie name=\"Internet Explorer\" rangeEnd=\"61\" rangeStart=\"61\"/>			<firefox name=\"Firefox\" rangeEnd=\"62\" rangeStart=\"62\"/>			<opera name=\"Opera\" rangeEnd=\"63\" rangeStart=\"63\"/>			<safari name=\"Safari\" rangeEnd=\"64\" rangeStart=\"64\"/>			<chrome name=\"Chrome\" rangeEnd=\"65\" rangeStart=\"65\"/>			<sleipnir name=\"Sleipnir\" rangeEnd=\"66\" rangeStart=\"66\"/>			<lunascape name=\"Lunascape\" rangeEnd=\"67\" rangeStart=\"67\"/>			<browser_others name=\"その他(ブラウザ)\" rangeEnd=\"68\" rangeStart=\"68\"/></browser>		<blog name=\"ブログ\" rangeEnd=\"70\" rangeStart=\"69\">			<blog_all name=\"ブログ全般\" rangeEnd=\"70\" rangeStart=\"70\"/></blog>				<website name=\"ウェブサイト\" rangeEnd=\"71\" rangeStart=\"71\"/></computer>	<game name=\"ゲーム\" rangeEnd=\"74\" rangeStart=\"72\">		<tv_game name=\"TVゲーム\" rangeEnd=\"73\" rangeStart=\"73\"/>		<portable_game name=\"ポータブルゲーム\" rangeEnd=\"74\" rangeStart=\"74\"/></game>		<electric_phone name=\"家電/携帯\" rangeEnd=\"92\" rangeStart=\"75\">		<phone name=\"携帯\" rangeEnd=\"79\" rangeStart=\"76\">			<docomo name=\"docomo\" rangeEnd=\"77\" rangeStart=\"77\"/>			<au name=\"au\" rangeEnd=\"78\" rangeStart=\"78\"/>			<softbank name=\"SoftBank\" rangeEnd=\"79\" rangeStart=\"79\"/>		</phone>		<tv name=\"テレビ\" rangeEnd=\"80\" rangeStart=\"80\"/>		<recoder name=\"各種レコーダー\" rangeEnd=\"81\" rangeStart=\"81\"/>		<projector name=\"プロジェクター\" rangeEnd=\"82\" rangeStart=\"82\"/>		<mp3player name=\"MP3プレーヤー\" rangeEnd=\"83\" rangeStart=\"83\"/>		<head_phone name=\"ヘッドフォン\" rangeEnd=\"84\" rangeStart=\"84\"/>		<speaker name=\"スピーカー\" rangeEnd=\"85\" rangeStart=\"85\"/>		<dictionary name=\"電子辞書\" rangeEnd=\"86\" rangeStart=\"86\"/>		<radio name=\"ラジオ\" rangeEnd=\"87\" rangeStart=\"87\"/>		<refrigerator name=\"冷蔵庫\" rangeEnd=\"88\" rangeStart=\"88\"/>		<washing_machine namel=\"洗濯機\" rangeEnd=\"89\" rangeStart=\"89\"/>		<cleaner name=\"掃除機\" rangeEnd=\"90\" rangeStart=\"90\"/>				<humidifier name=\"加湿器\" rangeEnd=\"91\" rangeStart=\"91\"/>		<air_conditioner name=\"エアコン\" rangeEnd=\"92\" rangeStart=\"92\"/>		</electric_phone>	<life name=\"生活\" rangeEnd=\"93\" rangeStart=\"93\"/>	<beauty_health name=\"美容/健康\" rangeEnd=\"94\" rangeStart=\"94\"/><trip_leisure name=\"旅行/レジャー\" rangeEnd=\"95\" rangeStart=\"95\"/>	<gamble name=\"ギャンブル\" rangeEnd=\"104\" rangeStart=\"96\">		<pachinko name=\"パチンコ\" rangeEnd=\"97\" rangeStart=\"97\"/>		<pachislo name=\"パチスロ\" rangeEnd=\"98\" rangeStart=\"98\"/>		<ma_jan name=\"麻雀\" rangeEnd=\"99\" rangeStart=\"99\"/>		<casino name=\"カジノ\" rangeEnd=\"100\" rangeStart=\"100\"/>		<horse_racing name=\"競馬\" rangeEnd=\"101\" rangeStart=\"101\"/>		<bicycle_race_motorboat name=\"競輪/競艇\" rangeEnd=\"102\" rangeStart=\"102\"/>		<toto name=\"宝くじ/toto\" rangeEnd=\"103\" rangeStart=\"103\"/><gamble_others name=\"その他(ギャンブル)\" rangeEnd=\"104\" rangeStart=\"104\"/></gamble>	<investment name=\"投資/資産運用\" rangeEnd=\"109\" rangeStart=\"105\">		<stock name=\"株\" rangeEnd=\"106\" rangeStart=\"106\"/>		<fx name=\"FX\" rangeEnd=\"107\" rangeStart=\"107\"/>		<exchange name=\"為替\" rangeEnd=\"108\" rangeStart=\"108\"/>		<asset_management name=\"投資信託\" rangeEnd=\"109\" rangeStart=\"109\"/></investment></root>");
	}

	/**
	 * インスタンスを取得する
	 * @return このクラスのインスタンス　
	 */
	public static CategoryManager getInstance(){
		if(_Instance == null)
			_Instance = new CategoryManager();
		return _Instance;
	}
		
	/**
	 * 最上位のカテゴリ郡を取得する
	 * @return 最上位のカテゴリ郡
	 */
	public List<String> getTopCategories(){
		List<String> list = new ArrayList<String>();
		
		Node root = _Doc.getLastChild();
		NodeList nodeList = root.getChildNodes();
		int length = nodeList.getLength();
		
		for(int i=0; i<length; i++){
			Node node = nodeList.item(i);
			String nodeName = node.getNodeName();
			if(nodeName.equals("#text"))
				continue;
			String name = ((Element)node).getAttribute("name");
			list.add(name);
		}
		return list;		
	}
	
	/**
	 * カテゴリを取得する
	 * @param decisions もう既に決定しているカテゴリ
	 * @param result 子のカテゴリリスト
	 */
	public void getCategories(List<String> decisions, List<String> result){ 
		Node root = _Doc.getLastChild();
		NodeList nodeList = root.getChildNodes();
		_ArrayWatchCurrent = -1;	// -1からスタート（ちょっとトリッキー）
		walkCategoryListGet(nodeList,decisions, result);
	}
	
	private void walkCategoryListGet(NodeList nodes, List<String> decisions, List<String> result){
		_ArrayWatchCurrent++;

		int length = nodes.getLength();
		
		if(_ArrayWatchCurrent == decisions.size()){
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				String dispName = ((Element)node).getAttribute("name");
				result.add(dispName);
			}			
		}
		else{
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				String dispName = ((Element)node).getAttribute("name");
				if(decisions.get(_ArrayWatchCurrent).equals(dispName)){
					walkCategoryListGet(node.getChildNodes(), decisions, result);
					break;
				}
			}
		}		
		_ArrayWatchCurrent--;
	}
	
	public int getCategoryID(List<String> decisions){
		Node root = _Doc.getLastChild();
		NodeList nodeList = root.getChildNodes();
		_ArrayWatchCurrent = -1;	// -1からスタート（ちょっとトリッキー）
		
		return walkCategoryIDGet(nodeList,decisions);
	}
	
	private int walkCategoryIDGet(NodeList nodes, List<String> decisions){
		_ArrayWatchCurrent++;
	
		int length = nodes.getLength();
		int categoryID = 0;
		
		if(_ArrayWatchCurrent == decisions.size() - 1){
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				String dispName = ((Element)node).getAttribute("name");
				if(decisions.get(_ArrayWatchCurrent).equals(dispName)){
					categoryID = Integer.valueOf(((Element)node).getAttribute("rangeStart"));
					break;
				}				
			}			
		}
		else{
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				String dispName = ((Element)node).getAttribute("name");
				if(decisions.get(_ArrayWatchCurrent).equals(dispName)){
					categoryID = walkCategoryIDGet(node.getChildNodes(), decisions);
					break;
				}
			}			
		}
		_ArrayWatchCurrent--;
		return categoryID;
	}
	
	public String getCategoryIDName(List<String> decisions){
		Node root = _Doc.getLastChild();
		NodeList nodeList = root.getChildNodes();
		StringBuilder sb = new StringBuilder();
		_ArrayWatchCurrent = -1;
		walkCategoryIDNameGet(nodeList,decisions, sb);
		return sb.toString();
	}
	
	private void walkCategoryIDNameGet(NodeList nodes, List<String> decisions, StringBuilder sb){
		_ArrayWatchCurrent++;
		int length = nodes.getLength();
		
		for(int i=0;i<length;i++){
			Node node = nodes.item(i);
			String nodeName = node.getNodeName();
			if(nodeName.equals("#text"))
				continue;
			String dispName = ((Element)node).getAttribute("name");
			if(decisions.get(_ArrayWatchCurrent).equals(dispName)){
				if(sb.length() != 0){
					sb.append(this.PathSeparator);
				}
				sb.append(nodeName);
				walkCategoryIDNameGet(node.getChildNodes(), decisions, sb);
				break;
			}
		}
		_ArrayWatchCurrent--;
	}
	public String getCategoryIDRange(String uri){
		return "111,222";
/*		Node root = _Doc.getLastChild();
		NodeList nodeList = root.getChildNodes();
		Pattern pattern = Pattern.compile("/browse/(.*)/index.jsp;");
		Matcher matcher = pattern.matcher(uri);
		String categoryPath = matcher.group(1);
		String[] cateArray = categoryPath.split("/");
		List<String> cateList = new ArrayList<String>();
		for(String s : cateArray){
			cateList.add(s);
		}		
		_ArrayWatchCurrent = -1;
		String result = walkCategoryIDRange(nodeList,cateList);
		return result;
*/	}
	
	private String walkCategoryIDRange(NodeList nodes, List<String> decisions){
		_ArrayWatchCurrent++;
		
		int length = nodes.getLength();
		String categoryRange = "";
		
		if(_ArrayWatchCurrent == decisions.size() - 1){
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				if(decisions.get(_ArrayWatchCurrent).equals(nodeName)){
					String start = ((Element)node).getAttribute("rangeStart");
					String end = ((Element)node).getAttribute("rangeEnd");
					categoryRange = start + "," + end;
					break;
				}				
			}			
		}
		else{
			for(int i=0;i<length;i++){
				Node node = nodes.item(i);
				String nodeName = node.getNodeName();
				if(nodeName.equals("#text"))
					continue;
				if(decisions.get(_ArrayWatchCurrent).equals(nodeName)){
					categoryRange = walkCategoryIDRange(node.getChildNodes(), decisions);
					break;
				}
			}
		}
		_ArrayWatchCurrent--;
		return categoryRange;
	}
}
